use alloc::string::{String, ToString};
use dev::DevScheme;
use fat32::Fat32Volume;
use spin::{Lazy, Mutex};
use syscall::scheme::SchemeRef;

use crate::ref_to_mut;

pub static ROOT_INODE: Lazy<Mutex<SchemeRef>> = Lazy::new(|| Mutex::new(DevScheme::new()));

pub mod cache;
pub mod dev;
pub mod disk;
pub mod fat32;
pub mod gpt_parser;
pub mod part;

pub static ROOT_PARTITION: Mutex<Option<SchemeRef>> = Mutex::new(None);

pub fn init() {
    self::dev::init();
    self::disk::init();

    let root_part = ROOT_PARTITION.lock();
    let root_part = root_part.as_ref().unwrap();
    let root_scheme = Fat32Volume::new(root_part.clone()).unwrap();

    let dev_scheme = ROOT_INODE.lock().read().open("dev".to_string()).unwrap();

    *ROOT_INODE.lock() = root_scheme.clone();

    dev_scheme.write().when_umounted();
    root_scheme.write().when_mounted("/".to_string(), None);

    mount_to(dev_scheme.clone(), root_scheme.clone(), "dev".to_string());
}

pub fn get_scheme_by_path(path: String) -> Option<SchemeRef> {
    let root = ROOT_INODE.lock().clone();

    let path = path.split("/");

    let node = root;

    for path_node in path {
        if path_node.len() > 0 {
            if let Some(child) = node.read().open(String::from(path_node)) {
                core::mem::drop(core::mem::replace(ref_to_mut(&node), child));
            } else {
                return None;
            }
        }
    }

    Some(node.clone())
}

pub fn mount_to(node: SchemeRef, to: SchemeRef, name: String) {
    to.write().mount(node.clone(), name.clone());
    node.write()
        .when_mounted(to.read().get_path() + &name + "/", Some(to.clone()));
}
